﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using AddIn.EA.Core.Interface;
using AddIn.EA.Core.Common;
using AddIn.EA.Framework;
using AddIn.EA.Framework.Common;
using AddIn.EA.Architecture.Presentation.Common;

namespace AddIn.EA.Architecture.Presentation
{
    public class UpdateEventArgs : EventArgs
    {
        public UpdateEventArgs(RepositoryManager repository)
        {
            this.Repository = repository;
            this.Updated = false;
        }

        /// <summary>
        /// Enterprise Arquitect Repository
        /// </summary>
        public RepositoryManager Repository { get; private set; }

        /// <summary>
        /// The state that defines if it was updated or not. Default is false.
        /// </summary>
        public bool Updated { get; set; }
    }

    public
#if !DESIGNER
        abstract
#endif
 class BaseAddInArchitecture : Form, IAddInArchitecture
    {
        #region Field
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        private string _formName = null;
        private bool _confirmUpdate = true;
        private bool _showCheckMessage = true;
        #endregion

        #region Constructor
        public BaseAddInArchitecture()
        {
            InitializeComponent();
            this.TabOrder = new ControlTabOrder();
            this.TabOrder.OnFirstTabIndex += new EventHandler<TabIndexEventArgs>(TabOrder_OnFirstTabIndex);
            this.TabOrder.OnLastTabIndex += new EventHandler<TabIndexEventArgs>(TabOrder_OnLastTabIndex);
            this.FormBorderStyle = FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;

        }
        #endregion

        #region Property
        /// <summary>
        /// the name of form displayed in form title.
        /// </summary>
        public virtual string FormName
        {
            get
            {
                if (_formName == null)
                    _formName = GetFormName();

                return _formName;
            }
        }
        /// <summary>
        /// Component to composite objects in tab order manually.
        /// </summary>
        protected Common.ControlTabOrder TabOrder { get; set; }
        /// <summary>
        /// Repository Object to manipulate the object model of Enterprise Architect
        /// </summary>
        protected RepositoryManager Repository { get; set; }

        /// <summary>
        /// Ask the user if it really want update the Enterprise Architect before close the form.
        /// Default is true. If set as false the repository will be updated automatically without confirmation.
        /// </summary>
        protected bool ConfirmUpdate
        {
            get { return _confirmUpdate; }
            set { _confirmUpdate = value; }
        }

        /// <summary>
        /// Show a message to user when the form cannot be displayed after "CheckShowForm" return false.
        /// </summary>
        protected bool ShowCheckMessage
        {
            get { return _showCheckMessage; }
            set { _showCheckMessage = false; }
        }
        #endregion

        public event EventHandler BeforeUpdateEA;
        public event EventHandler<UpdateEventArgs> OnUpdateEA;
        public event EventHandler AfterUpdateEA;
        public event EventHandler LoadAddInControls;
        public event EventHandler UnloadAddInControls;

        #region Events
        void TabOrder_OnLastTabIndex(object sender, TabIndexEventArgs e)
        {
            OnLastTabIndex(e);
        }

        void TabOrder_OnFirstTabIndex(object sender, TabIndexEventArgs e)
        {
            OnFirstTabIndex(e);
        }
        #endregion

        #region Protected Methods
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null || this.Repository != null))
            {
                if (components != null)
                    components.Dispose();

                if (this.Repository != null)
                    this.Repository.Dispose();
            }
            base.Dispose(disposing);
        }

        /// <summary>
        /// Update the Enterprise Architect when the user submit
        /// the form to close and the DialogResult of the form is equal to "OK".
        /// </summary>
        /// <param name="repository">The Enterprise Architect repository.</param>
        protected virtual bool UpdateEA(RepositoryManager repository)
        {
            if (BeforeUpdateEA != null)
                BeforeUpdateEA(this, new EventArgs());

            UpdateEventArgs args = new UpdateEventArgs(repository);
            if (OnUpdateEA != null)
                OnUpdateEA(this, args);

            if (AfterUpdateEA != null && args.Updated)
                AfterUpdateEA(this, new EventArgs());

            return args.Updated;
        }

#if !DESIGNER
        protected abstract bool CheckShowForm(IElement selectedElement, MenuLocation location);
#else
        protected virtual bool CheckShowForm(IElement selectedElement, MenuLocation location)
        {
            return true;
        }
#endif

        protected void HandleException(String operation, Exception ex)
        {
            HandleException(operation, ex, false);
        }
        protected void HandleException(String operation, Exception ex, Boolean detailedStackTrace)
        {
            MessageBox.Show("Ocorreu um erro durante a operação: " + operation + "\r\n\r\nDetalhes: " + (detailedStackTrace ? ex.ToString() : ex.Message), "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        protected virtual String GetBooleanYesNoDescription(bool value)
        {
            return value ? "Sim" : "Não";
        }
        #endregion

        #region Private Methods
        private void frmBase_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this.DialogResult == DialogResult.OK)
            {
                DialogResult result = DialogResult.Yes;

                if (this.ConfirmUpdate)
                    result = MessageBox.Show("Do you really want update the Enterprise Architect?", "Update Enterprise Architect", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

                if (result == DialogResult.Yes)
                {
                    if (UpdateEA(this.Repository))
                    {
                        if (UnloadAddInControls != null)
                            UnloadAddInControls(this, new EventArgs());

                        this.Hide();
                    }
#if DESIGNER
                    else
                        e.Cancel = true;
#endif
                }
#if DESIGNER
                else
                {
                    e.Cancel = true;
                }
#endif
            }
            else
            {
                if (UnloadAddInControls != null)
                    UnloadAddInControls(this, new EventArgs());

#if DESIGNER
                e.Cancel = true;
#endif
                this.Hide();
            }

            this.DialogResult = DialogResult.None;
#if !DESIGNER
            e.Cancel = true;
#endif
        }

        private string GetFormName()
        {
            string formName = string.Empty;

            object[] attrib = this.GetType().GetCustomAttributes(typeof(AddInMenuAttribute), true);

            if (attrib.Length > 0)
                formName = ((AddInMenuAttribute)attrib[0]).ItemDescription;

            return formName;
        }

        protected virtual void OnFirstTabIndex(TabIndexEventArgs e)
        {
            this.TabOrder.MoveToLast();
        }

        protected virtual void OnLastTabIndex(TabIndexEventArgs e)
        {
            this.TabOrder.MoveToFirst();
        }
        #endregion

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // frmBase
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(292, 273);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
            this.Name = "frmBase";
#if DESIGNER
            this.Text = "<The description of menu item>";
            this.ShowInTaskbar = true;
#else
            this.Text = this.FormName;
            this.DialogResult = DialogResult.None;
            this.TopMost = true;
            this.ShowInTaskbar = false;
#endif
            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmBase_FormClosing);
            this.ResumeLayout(false);

        }

        #endregion

        #region IAddInArchitecture Members

        /// <summary>
        /// Check the state to execute the add-in
        /// </summary>
        /// <param name="repository">Repository Object</param>
        /// <param name="menuLocation">Location of Menu Clicked by user.</param>
        /// <returns>If the add-in can be executed. Default true.</returns>
        public virtual bool CheckState(EA_Application.Repository repository, MenuLocation menuLocation)
        {
            this.Repository = RepositoryManager.LoadManager(repository);

            IElement selectedElement = this.Repository.GetSelectedObject();

            bool showForm = CheckShowForm(selectedElement, menuLocation);

            if (!showForm && this.ShowCheckMessage)
                MessageBox.Show("O add-in selecionado não pode ser exibido nesse contexto!", "Alert", MessageBoxButtons.OK, MessageBoxIcon.Stop);

            return showForm;
        }

        public virtual void Execute(EA_Application.Repository repository, MenuLocation menuLocation)
        {
            if (LoadAddInControls != null)
                LoadAddInControls(this, new EventArgs());

            this.Show();
        }

        #endregion
    }
}
